{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "function.ipynb",
      "provenance": [],
      "private_outputs": true,
      "collapsed_sections": [
        "Jxv6goXm7oGF"
      ],
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "Jxv6goXm7oGF"
      },
      "source": [
        "##### Copyright 2018 The TensorFlow Authors.\n",
        "\n",
        "Licensed under the Apache License, Version 2.0 (the \"License\");"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "llMNufAK7nfK",
        "colab": {}
      },
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\"); { display-mode: \"form\" }\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "8Byow2J6LaPl"
      },
      "source": [
        "# 텐서플로 2.0의 tf.function과 오토그래프 (AutoGraph)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "kGXS3UWBBNoc"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://www.tensorflow.org/guide/function\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\" />TensorFlow.org 에서 보기</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs/blob/master/site/ko/guide/function.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\" />구글 코랩(Google Colab)에서 실행하기</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://github.com/tensorflow/docs/blob/master/site/ko/guide/function.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\" />깃헙(GitHub) 소스 보기</a>\n",
        "  </td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "GQLxpmF2_AvM",
        "colab_type": "text"
      },
      "source": [
        "Note: 이 문서는 텐서플로 커뮤니티에서 번역했습니다. 커뮤니티 번역 활동의 특성상 정확한 번역과 최신 내용을 반영하기 위해 노력함에도\n",
        "불구하고 [공식 영문 문서](https://www.tensorflow.org/?hl=en)의 내용과 일치하지 않을 수 있습니다.\n",
        "이 번역에 개선할 부분이 있다면\n",
        "[tensorflow/docs](https://github.com/tensorflow/docs) 깃헙 저장소로 풀 리퀘스트를 보내주시기 바랍니다.\n",
        "문서 번역이나 리뷰에 참여하려면\n",
        "[docs-ko@tensorflow.org](https://groups.google.com/a/tensorflow.org/forum/#!forum/docs-ko)로\n",
        "메일을 보내주시기 바랍니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "CydFK2CL7ZHA"
      },
      "source": [
        "TF 2.0 버전은 즉시 실행 (eager execution)의 편리함과 TF 1.0의 성능을 합쳤습니다. 이러한 결합의 중심에는 `tf.function` 이 있는데, 이는 파이썬 문법의 일부를 이식 가능하고 높은 성능의 텐서플로 그래프 코드로 변환시켜줍니다. \n",
        "\n",
        "`tf.function`의 멋지고 새로운 특징은 오토그래프 (AutoGraph)입니다. 이는 자연스러운 파이썬 문법을 활용해서 그래프 코드를 작성할 수 있도록 돕습니다. 오토그래프로 사용할 수 있는 파이썬 특징들의 목록을 보려면 [오토그래프 지원 범위](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/autograph/LIMITATIONS.md)를 참고하세요. `tf.function`에 관한 더 자세한 내용을 확인하려면 RFC [TF 2.0: Functions, not Sessions](https://github.com/tensorflow/community/blob/master/rfcs/20180918-functions-not-sessions-20.md)을 참고하세요. 오토그래프에 대한 더 자세한 내용은 `tf.autograph`를 참고하세요.\n",
        "\n",
        "본 튜토리얼은 `tf.function`와 오토그래프의 기초적인 특징에 대해서 설명할 것입니다. "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "n4EKOpw9mObL"
      },
      "source": [
        "## 설정\n",
        "\n",
        "텐서플로 2.0 프리뷰 나이틀리 (Preview Nightly) 버전을 임포트(import)하고, TF 2.0 모드를 설정합니다:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "V9oECvVSI1Kj",
        "colab": {}
      },
      "source": [
        "from __future__ import absolute_import, division, print_function, unicode_literals\n",
        "import numpy as np"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "mT7meGqrZTz9",
        "colab": {}
      },
      "source": [
        "!pip install tensorflow==2.0.0-beta1\n",
        "import tensorflow as tf"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "77AsVr1GGtBP"
      },
      "source": [
        "## `tf.function` 데코레이터\n",
        "\n",
        "`tf.function`을 함수에 붙여줄 경우, 여전히 다른 일반 함수들처럼 사용할 수 있습니다. 하지만 그래프 내에서 컴파일 되었을 때는 더 빠르게 실행하고, GPU나 TPU를 사용해서 작동하고, 세이브드모델(SavedModel)로 내보내는 것이 가능해집니다."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "FhIg7-z6HNWj",
        "colab": {}
      },
      "source": [
        "@tf.function\n",
        "def simple_nn_layer(x, y):\n",
        "  return tf.nn.relu(tf.matmul(x, y))\n",
        "\n",
        "\n",
        "x = tf.random.uniform((3, 3))\n",
        "y = tf.random.uniform((3, 3))\n",
        "\n",
        "simple_nn_layer(x, y)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "U-LAE4pMNR9g"
      },
      "source": [
        "데코레이터를 붙인 결과를 확인해보면, 텐서플로 런타임시의 모든 상호작용들을 다룰 수 있다는 것을 알 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "q4t2iuS7Nqc0",
        "colab": {}
      },
      "source": [
        "simple_nn_layer"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "DqeefLGNXjZQ"
      },
      "source": [
        "만일 여러분의 코드가 여러 함수들을 포함하고 있다면, 그것들에 모두 데코레이터를 붙일 필요는 없습니다. 데코레이터가 붙은 함수로부터 호출된 모든 함수들은 그래프 모드에서 동작합니다."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "3VGF7tlVXiZY",
        "colab": {}
      },
      "source": [
        "def linear_layer(x):\n",
        "  return 2 * x + 1\n",
        "\n",
        "\n",
        "@tf.function\n",
        "def deep_net(x):\n",
        "  return tf.nn.relu(linear_layer(x))\n",
        "\n",
        "\n",
        "deep_net(tf.constant((1, 2, 3)))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "yQvg6ZSKWyqE"
      },
      "source": [
        "작은 연산들을 많이 포함한 그래프의 경우 함수들은 즉시 실행 코드 (eager code) 보다 더 빠르게 동작합니다. 하지만 무거운 연산들을 조금 포함한 그래프의 경우 (컨볼루션 등), 그렇게 빠른 속도 향상은 기대하기 어렵습니다.\n"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "0EL6lVwEWuFo",
        "colab": {}
      },
      "source": [
        "import timeit\n",
        "conv_layer = tf.keras.layers.Conv2D(100, 3)\n",
        "\n",
        "@tf.function\n",
        "def conv_fn(image):\n",
        "  return conv_layer(image)\n",
        "\n",
        "image = tf.zeros([1, 200, 200, 100])\n",
        "# 데이터 준비 (warm up)\n",
        "conv_layer(image); conv_fn(image)\n",
        "print(\"컨볼루션 즉시 실행:\", timeit.timeit(lambda: conv_layer(image), number=10))\n",
        "print(\"컨볼루션 함수:\", timeit.timeit(lambda: conv_fn(image), number=10))\n",
        "print(\"컨볼루션의 성능에는 큰 차이가 없다는 것을 확인할 수 있습니다\")\n"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "L4zj-jpH0jKH",
        "colab": {}
      },
      "source": [
        "lstm_cell = tf.keras.layers.LSTMCell(10)\n",
        "\n",
        "@tf.function\n",
        "def lstm_fn(input, state):\n",
        "  return lstm_cell(input, state)\n",
        "\n",
        "input = tf.zeros([10, 10])\n",
        "state = [tf.zeros([10, 10])] * 2\n",
        "# 데이터 준비 (warm up)\n",
        "lstm_cell(input, state); lstm_fn(input, state)\n",
        "print(\"lstm 즉시 실행:\", timeit.timeit(lambda: lstm_cell(input, state), number=10))\n",
        "print(\"lstm 함수:\", timeit.timeit(lambda: lstm_fn(input, state), number=10))\n"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "ohbSnA79mcJV"
      },
      "source": [
        "## 파이썬의 제어 흐름 사용하기\n",
        "\n",
        "`tf.function` 내에서 데이터 기반 제어 흐름을 사용할 때, 파이썬의 제어 흐름 문을 사용할 수 있고, 오토그래프 기능은 그것들을 모두 적절한 텐서플로 연산으로 변환할 수 있습니다. 예를 들어, `if` 문은 `Tensor`를 기반으로 작동해야할 때 `tf.cond()` 로 변환될 수 있습니다. \n",
        "\n",
        "아래 예시에서, `x`는 `Tensor`이지만 `if`문이 예상한대로 정상 작동합니다:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "aA3gOodCBkOw",
        "colab": {}
      },
      "source": [
        "@tf.function\n",
        "def square_if_positive(x):\n",
        "  if x > 0:\n",
        "    x = x * x\n",
        "  else:\n",
        "    x = 0\n",
        "  return x\n",
        "\n",
        "\n",
        "print('square_if_positive(2) = {}'.format(square_if_positive(tf.constant(2))))\n",
        "print('square_if_positive(-2) = {}'.format(square_if_positive(tf.constant(-2))))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "GMiCUkdyoq98"
      },
      "source": [
        "Note: 위의 예시는 스칼라값으로 간단한 조건절을 사용하였습니다. 하지만 실제 코드에서는 <a href=\"#batching\">배치(Batching)</a> 가 주로 사용됩니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "m-jWmsCmByyw"
      },
      "source": [
        "오토그래프는 기본적인 파이썬 문인 `while`, `for`, `if`, `break`, `continue`, `return`과 네스팅(nesting)을 지원합니다. 이는 `Tensor` 표현을 `while`과 `if` 문의 조건 부분에서 사용하거나 `for` 루프에서 `Tensor`를 반복할 수 있다는 것을 의미합니다."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "toxKBOXbB1ro",
        "colab": {}
      },
      "source": [
        "@tf.function\n",
        "def sum_even(items):\n",
        "  s = 0\n",
        "  for c in items:\n",
        "    if c % 2 > 0:\n",
        "      continue\n",
        "    s += c\n",
        "  return s\n",
        "\n",
        "\n",
        "sum_even(tf.constant([10, 12, 15, 20]))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "AtDaLrbySw4j"
      },
      "source": [
        "또한 오토그래프는 고급 사용자를 위해 낮은 수준의 API를 제공합니다. 예를 들어, 여러분은 생성된 코드를 확인하기 위해 다음과 같이 작성할 수 있습니다. "
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "aRsde3x_SjTQ",
        "colab": {}
      },
      "source": [
        "print(tf.autograph.to_code(sum_even.python_function))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "rvJXCfk8VkLf"
      },
      "source": [
        "다음은 더 복잡한 제어 흐름의 예시입니다:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "h-Z87IJqVlKl",
        "colab": {}
      },
      "source": [
        "@tf.function\n",
        "def fizzbuzz(n):\n",
        "  msg = tf.constant('')\n",
        "  for i in tf.range(n):\n",
        "    if tf.equal(i % 3, 0):\n",
        "      tf.print('Fizz')\n",
        "    elif tf.equal(i % 5, 0):\n",
        "      tf.print('Buzz')\n",
        "    else:\n",
        "      tf.print(i)\n",
        "\n",
        "fizzbuzz(tf.constant(15))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "h_Y4uC1R1B55"
      },
      "source": [
        "## 케라스와 오토그래프\n",
        "\n",
        "오토그래프는 기본적으로 비동적(non-dynamic) 케라스 모델에서 사용 가능합니다. 더 자세한 정보를 원한다면, `tf.keras`를 참고하세요."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "cR6mpLKP1HLe",
        "colab": {}
      },
      "source": [
        "class CustomModel(tf.keras.models.Model):\n",
        "\n",
        "  @tf.function\n",
        "  def call(self, input_data):\n",
        "    if tf.reduce_mean(input_data) > 0:\n",
        "      return input_data\n",
        "    else:\n",
        "      return input_data // 2\n",
        "\n",
        "\n",
        "model = CustomModel()\n",
        "\n",
        "model(tf.constant([-2, -4]))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "NTEvpBK9f8kj"
      },
      "source": [
        "## 부수 효과 (Side effects)\n",
        "\n",
        "즉시 실행 모드 (eager mode)처럼 부수 효과를 사용할 수 있습니다. 예를 들면, `tf.function` 내에 있는 `tf.assign`이나 `tf.print`이 있습니다. 또한 부수 효과들은 작업들이 순서대로 실행된다는 것을 보장하기 위해 필수적인 제어 의존성 (control dependency)을 추가합니다."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "-Wd6i8S9gcuC",
        "colab": {}
      },
      "source": [
        "v = tf.Variable(5)\n",
        "\n",
        "@tf.function\n",
        "def find_next_odd():\n",
        "  v.assign(v + 1)\n",
        "  if tf.equal(v % 2, 0):\n",
        "    v.assign(v + 1)\n",
        "\n",
        "\n",
        "find_next_odd()\n",
        "v"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "4LfnJjm0Bm0B"
      },
      "source": [
        "## 디버깅\n",
        "\n",
        "`tf.function` 과 오토그래프는 코드를 생성하고 텐서플로 그래프 내에서 해당 코드를 추적함으로써 동작합니다. 이 메커니즘은 아직까지는 `pdb`같은 단계적 (step-by-step) 디버거를 지원하지 않습니다. 하지만 일시적으로 `tf.function` 내에서 즉시 실행 (eager execution)을 가능하게 하는 `tf.config.run_functions_eagerly(True)`을 사용하고 가장 선호하는 디버거를 사용할 수 있습니다:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "Yci8ve6hmgpF",
        "colab": {}
      },
      "source": [
        "@tf.function\n",
        "def f(x):\n",
        "  if x > 0:\n",
        "    # 여기에 중단점(breakpoint)을 설정해 보세요!\n",
        "    # 예시:\n",
        "    #   import pdb\n",
        "    #   pdb.set_trace()\n",
        "    x = x + 1\n",
        "  return x\n",
        "\n",
        "tf.config.experimental_run_functions_eagerly(True)\n",
        "\n",
        "# 이제 중단점을 설정하고 디버거 내에서 코드를 실행할 수 있습니다.\n",
        "f(tf.constant(1))\n",
        "\n",
        "tf.config.experimental_run_functions_eagerly(False)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "Em5dzSUOtLRP"
      },
      "source": [
        "### 데이터 다운로드"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "xqoxumv0ssQW",
        "colab": {}
      },
      "source": [
        "def prepare_mnist_features_and_labels(x, y):\n",
        "  x = tf.cast(x, tf.float32) / 255.0\n",
        "  y = tf.cast(y, tf.int64)\n",
        "  return x, y\n",
        "\n",
        "def mnist_dataset():\n",
        "  (x, y), _ = tf.keras.datasets.mnist.load_data()\n",
        "  ds = tf.data.Dataset.from_tensor_slices((x, y))\n",
        "  ds = ds.map(prepare_mnist_features_and_labels)\n",
        "  ds = ds.take(20000).shuffle(20000).batch(100)\n",
        "  return ds\n",
        "\n",
        "train_dataset = mnist_dataset()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "znmy4l8ntMvW"
      },
      "source": [
        "### 모델 정의하기"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "ltxyJVWTqNAO",
        "colab": {}
      },
      "source": [
        "model = tf.keras.Sequential((\n",
        "    tf.keras.layers.Reshape(target_shape=(28 * 28,), input_shape=(28, 28)),\n",
        "    tf.keras.layers.Dense(100, activation='relu'),\n",
        "    tf.keras.layers.Dense(100, activation='relu'),\n",
        "    tf.keras.layers.Dense(10)))\n",
        "model.build()\n",
        "optimizer = tf.keras.optimizers.Adam()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "oeYV6mKnJGMr"
      },
      "source": [
        "### 훈련 (training) 루프 정의하기"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "3xtg_MMhJETd",
        "colab": {}
      },
      "source": [
        "compute_loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)\n",
        "\n",
        "compute_accuracy = tf.keras.metrics.SparseCategoricalAccuracy()\n",
        "\n",
        "\n",
        "def train_one_step(model, optimizer, x, y):\n",
        "  with tf.GradientTape() as tape:\n",
        "    logits = model(x)\n",
        "    loss = compute_loss(y, logits)\n",
        "\n",
        "  grads = tape.gradient(loss, model.trainable_variables)\n",
        "  optimizer.apply_gradients(zip(grads, model.trainable_variables))\n",
        "\n",
        "  compute_accuracy(y, logits)\n",
        "  return loss\n",
        "\n",
        "\n",
        "@tf.function\n",
        "def train(model, optimizer):\n",
        "  train_ds = mnist_dataset()\n",
        "  step = 0\n",
        "  loss = 0.0\n",
        "  accuracy = 0.0\n",
        "  for x, y in train_ds:\n",
        "    step += 1\n",
        "    loss = train_one_step(model, optimizer, x, y)\n",
        "    if tf.equal(step % 10, 0):\n",
        "      tf.print('스텝', step, ': 손실', loss, '; 정확도', compute_accuracy.result())\n",
        "  return step, loss, accuracy\n",
        "\n",
        "step, loss, accuracy = train(model, optimizer)\n",
        "print('최종 스텝', step, ': 손실', loss, '; 정확도', compute_accuracy.result())"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "SnsumiP6eRYL"
      },
      "source": [
        "## 배치 (Batching)\n",
        "\n",
        "실제 적용시에 배치 (batch) 는 성능을 위해 필수적입니다. 오토그래프로 변환하기 가장 좋은 코드는 제어 흐름이 _배치_ 수준에서 결정되는 코드입니다. 만일 제어 흐름이 개별적인 _예제 (example)_ 수준에서 결정된다면, 성능을 유지하기 위해서 배치 API들을 사용해야합니다.\n",
        "\n",
        "예를 들어, 파이썬으로 다음과 같은 코드를 작성했다면:\n"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "t31QoERiNccJ",
        "colab": {}
      },
      "source": [
        "def square_if_positive(x):\n",
        "  return [i ** 2 if i > 0 else i for i in x]\n",
        "\n",
        "\n",
        "square_if_positive(range(-5, 5))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "kSeEJ76uNgwD"
      },
      "source": [
        "텐서플로에서는 다음과 같이 작성하고 싶을 것입니다. (그리고 다음 코드는 실제로 동작합니다!):\n"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "RqR8WzSzNf87",
        "colab": {}
      },
      "source": [
        "@tf.function\n",
        "def square_if_positive_naive(x):\n",
        "  result = tf.TensorArray(tf.int32, size=x.shape[0])\n",
        "  for i in tf.range(x.shape[0]):\n",
        "    if x[i] > 0:\n",
        "      result = result.write(i, x[i] ** 2)\n",
        "    else:\n",
        "      result = result.write(i, x[i])\n",
        "  return result.stack()\n",
        "\n",
        "\n",
        "square_if_positive_naive(tf.range(-5, 5))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "gTcyWXVGN3gS"
      },
      "source": [
        "하지만 이 경우는 아래와 같이 작성할 수도 있습니다:\n"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "VO2f6x-lNfVj",
        "colab": {}
      },
      "source": [
        "def square_if_positive_vectorized(x):\n",
        "  return tf.where(x > 0, x ** 2, x)\n",
        "\n",
        "\n",
        "square_if_positive_vectorized(tf.range(-5, 5))"
      ],
      "execution_count": 0,
      "outputs": []
    }
  ]
}